package ec.cd.client;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.content.res.Configuration;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.Editable;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.*;

import ec.cd.client.Networking.Client;
import ec.cd.common.Networking.BodyLocation;

public class ECCDClient extends Activity {
    private static String TAG = "ECCDClient";

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorsManager = new SensorsManager(this);

        serverIPText = (EditText)findViewById(R.id.server_ip);
        serverPortText = (EditText)findViewById(R.id.server_port);
        bodyLocationSpinner = (Spinner)findViewById(R.id.body_location);
        connectServerBtn = (Button)findViewById(R.id.connect_server);
        clientLogsScrollView =
            (ScrollView)findViewById(R.id.client_logs_scroll);
        clientLogsTextView = (TextView)findViewById(R.id.client_logs);
        connectionClient = new Client(
                this, clientLogsTextView,
                sensorsManager, _client_connection_evt);

        // serverIPText
        InputFilter[] filters = new InputFilter[1];
        filters[0] = _ip_validator;
        serverIPText.setFilters(filters);

        // bodyLocationSpinner
        ArrayAdapter<CharSequence> aa = ArrayAdapter.createFromResource(
                this, R.array.body_locations,
                android.R.layout.simple_spinner_item);
        aa.setDropDownViewResource(
                android.R.layout.simple_spinner_dropdown_item);
        bodyLocationSpinner.setAdapter(aa);

        // connectServerBtn
        connectServerBtn.setOnClickListener(_connect_server_click);

        // clientLogsScrollView
        clientLogsScrollView.setSmoothScrollingEnabled(true);

        // clientLogsTextView
        clientLogsTextView.addTextChangedListener(
                _client_logs_text_changed_evt);
    }

    @Override
    protected void onPause() {
        super.onPause();

        sensorsManager.stopListening();
    }

    @Override
    protected void onResume() {
        super.onResume();

        sensorsManager.startListening();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        sensorsManager.stopListening();
    }

    private InputFilter _ip_validator = new InputFilter() {
        public CharSequence filter(CharSequence source, int start, int end,
                Spanned dest, int dstart, int dend) {
            if (end > start) {
                String dst = dest.toString();
                String res = dst.substring(0, dstart)
                        + source.subSequence(start, end)
                        + dst.substring(dend);
                if (!res.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
                    return "";
                } else {
                    for (String s : res.split("\\.")) {
                        if (Integer.valueOf(s) > 255)
                            return "";
                    }
                }
            }

            return null;
        }
    };

    // Should never return an invalid location
    private BodyLocation getSelectedBodyLocation() {
        BodyLocation ret = BodyLocation.Torso; // 0
        switch (bodyLocationSpinner.getSelectedItemPosition()) {
            case 1:
                ret = BodyLocation.Arm;
                break;
            case 2:
                ret = BodyLocation.Leg;
                break;
        }

        return ret;
    }

    private class ConnectTask extends AsyncTask<String, Void, Boolean> {
        protected void onPreExecute() {
            connectServerBtn.setEnabled(false);
            clientLogsTextView.append("Connecting...\n");
        }

        // If not connected, ss must contain host and port
        protected Boolean doInBackground(String... ss) {
            if (ss[0].length() > 0 && ss[1].length() > 0) {
                return connectionClient.connect(ss[0], Integer.parseInt(ss[1]));
            }

            return false;
        }

        protected void onPostExecute(Boolean res) {
            if (res) {
                clientLogsTextView.append("Connection established\n");
                connectServerBtn.setText(getString(R.string.disconnect_server));

                // Get additional params and start handling the connection
                connectionClient.handleConnection(getSelectedBodyLocation());
            } else {
                clientLogsTextView.append("Connection failed\n");
            }
            connectServerBtn.setEnabled(true);
        }
    }
    private class DisconnectTask extends AsyncTask<Void, Void, Void> {
        protected void onPreExecute() {
            connectServerBtn.setEnabled(false);
            clientLogsTextView.append("Disconnecting...\n");
        }

        protected Void doInBackground(Void... objs) {
            connectionClient.disconnect();

            return null;
        }

        protected void onPostExecute(Void res) {
            clientLogsTextView.append("Disconnected\n");
            connectServerBtn.setText(getString(R.string.connect_server));
            connectServerBtn.setEnabled(true);
        }
    }
    private View.OnClickListener _connect_server_click =
            new View.OnClickListener() {
                public void onClick(View v) {
                    if (!connectionClient.connected()) {
                        new ConnectTask().execute(
                                serverIPText.getText().toString(),
                                serverPortText.getText().toString());
                    } else new DisconnectTask().executeOnExecutor(
                            AsyncTask.THREAD_POOL_EXECUTOR);
                }
            };

    private Client.ConnectionEventListener _client_connection_evt =
        new Client.ConnectionEventListener() {
            public void disconnected() {
                connectServerBtn.setText(getString(R.string.connect_server));
            }
        };

    private Runnable _client_logs_autoscroll =
        new Runnable() {
            public void run() {
                clientLogsScrollView.smoothScrollTo(
                        0, clientLogsTextView.getBottom());
            }
        };
    private TextWatcher _client_logs_text_changed_evt =
        new TextWatcher() {
            public void afterTextChanged(Editable s) {
                clientLogsScrollView.post(_client_logs_autoscroll);
            }

            public void beforeTextChanged(CharSequence s, int start,
                                          int count, int after) {}

            public void onTextChanged(CharSequence s, int start,
                                      int before, int count) {}
        };

    private SensorsManager sensorsManager;
    private EditText serverIPText;
    private EditText serverPortText;
    private Spinner bodyLocationSpinner;
    private Button connectServerBtn;
    private ScrollView clientLogsScrollView;
    private TextView clientLogsTextView;
    private Client connectionClient;
}
